home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / Database / AddressBook / AddressView.m < prev    next >
Text File  |  1995-06-12  |  11KB  |  404 lines

  1. /* AddressView.m:
  2.  * You may freely copy, distribute, and reuse the code in this example.
  3.  * NeXT disclaims any warranty of any kind, expressed or  implied, as to its
  4.  * fitness for any particular use.
  5.  *
  6.  * Written by Mai Nguyen, NeXT Developer Support
  7.  *
  8.  */
  9.  
  10. #import <appkit/appkit.h>
  11. #import <objc/List.h>
  12. #import <dbkit/DBRecordList.h>
  13. #import <dbkit/DBValue.h>
  14. #import <libc.h>
  15.  
  16. #import "AddressView.h"
  17. #import "Controller.h"
  18.  
  19. #define EMPTY_STRING NXLocalizedString("Cannot accept empty string", NULL, "Notify user that empty string input is not valid.")
  20.  
  21. static char cellName[100];
  22.  
  23. @implementation AddressView
  24.  
  25. - initFrame:(const NXRect *)frameRect
  26. {
  27.       NXSize interCellSpacing = {0.0, 0.0}, docSize;
  28.  
  29.   [    super initFrame:frameRect];
  30.       cellMatrix = [[Matrix alloc] initFrame:frameRect
  31.         mode:NX_LISTMODE
  32.         cellClass:[TextFieldCell class]
  33.         numRows:0
  34.         numCols:1];
  35.  
  36.       /*
  37.        * In the following lines,
  38.        * remember that "cellMatrix" is the matrix that will be installed
  39.        * in the scrollview, "self" is the scrollview.
  40.        */
  41.  
  42.           /* we don't want any space between the matrix's cells  */
  43.       [cellMatrix setIntercell:&interCellSpacing];
  44.           /* resize the matrix to contain the cells */
  45.      [cellMatrix sizeToCells];
  46.       [cellMatrix setAutosizeCells:YES];
  47.     
  48.       /*
  49.        * when the user clicks in the matrix and then drags the mouse out of
  50.        * scrollView's contentView, we want the matrix to scroll
  51.        */
  52.       [cellMatrix setAutoscroll:YES];
  53.           /* let the matrix stretch horizontally */
  54.       [cellMatrix setAutosizing:NX_WIDTHSIZABLE];  
  55.           /* Install the matrix as the docview of the scrollview */
  56.       [[self setDocView:cellMatrix] free];
  57.           /* set up the visible attributes of the scrollview */
  58.       [self setVertScrollerRequired:YES];
  59.       [self setBorderType:NX_BEZEL];
  60.           /* tell the subviews to resize along with the scrollview */
  61.       [self setAutoresizeSubviews:YES];
  62.           /* This is the only way to get the clipview to resize too */
  63.       [[cellMatrix superview] setAutoresizeSubviews:YES];
  64.           /* Allow the scrollview to stretch both horizontally and vertically */
  65.       [self setAutosizing:NX_WIDTHSIZABLE|NX_HEIGHTSIZABLE];
  66.           /* Resize the matrix to fill the inside of the scrollview */
  67.      [self getContentSize:&docSize];
  68.        [cellMatrix sizeTo:docSize.width :docSize.height];
  69.  
  70.     /* Set the matrix single click action */
  71.     [cellMatrix setTarget:self];
  72.       [cellMatrix setAction:@selector(showInfo:)];
  73.       
  74.     /* Allocate DBValue instances for accessing record contents */
  75.     aValue = [[DBValue alloc] init];
  76.     aValue2 = [[DBValue alloc] init];
  77.     return self;
  78. }
  79.  
  80. - free
  81. {
  82.       [cellMatrix free];
  83.      if (aValue)
  84.          [aValue free];
  85.     if (aValue2)
  86.         [aValue2 free];
  87.       return [super free];
  88. }
  89.  
  90. - cellMatrix
  91. {
  92.       return cellMatrix;
  93. }
  94.  
  95. /*
  96.  * Since we recycle the cells (via renewRows:cols:), we also set the state
  97.  * of each cell to 0 and unhighlight it.  If we don't do that, the recycled
  98.  * cells will display their previous state.
  99.  */
  100. - loadCellsFrom:sender
  101.  
  102. {
  103.     int i, cellCount;
  104.      const char *firstName, *lastName;
  105.     char buf[100];
  106.     DBRecordList *    recordList;
  107.     List *    propertyList;
  108.           
  109.     recordList = (DBRecordList *)[controller getRecordList];
  110.     propertyList = (List *)[controller getPropertyList];
  111.     cellCount = (int) [controller getRecordCount];
  112.     
  113.      if (cellCount == 0 )
  114.           return self;
  115.   
  116.        
  117.         /* tell the matrix there are 0 cells in it (but don't deallocate them) */
  118.       [cellMatrix renewRows:0 cols:1];
  119.       [cellMatrix lockFocus];        /* for highlightCellAt::lit: */
  120.       for (i=0;i<cellCount;i++) {
  121.         TextFieldCell *cell;
  122.             /*
  123.          * add a row to the matrix.  (This doesn't necessarily allocate a new
  124.          * cell, thanks to renewRows:cols:).
  125.          */
  126.         [cellMatrix addRow];
  127.         cell = [cellMatrix cellAt:i:0];
  128.             /* make sure the cell is neither selected nor highlighted */
  129.             [cellMatrix highlightCellAt:i:0 lit:NO];
  130.         [cell setState:0];
  131.         
  132.         /* install the string value in that cell */
  133.         [recordList getValue:aValue 
  134.                     forProperty:[propertyList objectAt:1]at:i];                                             
  135.         lastName= (const char *)[aValue stringValue];
  136.  
  137.         [recordList getValue:aValue2 
  138.                     forProperty:[propertyList objectAt:2]at:i];                                                         
  139.         firstName = (const char *)[aValue2 stringValue];
  140.         sprintf(buf, "%s %s", lastName, firstName);
  141.         [cell setStringValue:buf];
  142.         
  143.       }
  144.       [cellMatrix unlockFocus];
  145.       [cellMatrix sizeToCells];
  146.       [cellMatrix display];
  147.       
  148.       return self;
  149. }
  150.  
  151. /* Get the newly added row */
  152. - (int) getNewRow
  153. {
  154.     int i;
  155.     int count, row;
  156.     const char* name;
  157.     
  158.     count = [cellMatrix cellCount];
  159.     row = count;     /* Initialize row to a meaningful number */
  160.     for (i = 0; i < count; i++) {
  161.         name = [[cellMatrix cellAt:i:0] stringValue];
  162.         if (!strcmp(cellName, name) ) {
  163.             row = i;
  164.             break;
  165.         }
  166.     }
  167.     return row;
  168. }
  169.  
  170.  
  171. /* Show the information contained in each selected record
  172.  */
  173.  
  174. - showInfo:sender
  175. {
  176.     int index;
  177.     DBRecordList * recordList;
  178.     List *    propertyList;
  179.  
  180.     recordList = [controller getRecordList];
  181.     propertyList = [controller getPropertyList];
  182.  
  183.     index = [cellMatrix selectedRow];
  184.  
  185.         /* Find the person's id    */
  186.     
  187.     [recordList getValue:aValue forProperty:[propertyList objectAt:0]at:index];                                                                                                                                      
  188.     [ssnField setStringValue:(const char *)[aValue stringValue]];
  189.  
  190.  
  191.         /* Find the person's last name and first name */
  192.     [recordList getValue:aValue forProperty:[propertyList objectAt:1]at:index];                                                                                                                                      
  193.     [lnameField setStringValue: (const char *)[aValue stringValue]];
  194.  
  195.     [recordList getValue:aValue forProperty:[propertyList objectAt:2]at:index];                                                                     
  196.     [fnameField setStringValue:(const char *)[aValue stringValue]];
  197.  
  198.                 /* Find the person's phone number */
  199.     [recordList getValue:aValue forProperty:[propertyList objectAt:3]at:index];                                                                                                                                  
  200.     [phoneField setStringValue:(const char *)[aValue stringValue]];
  201.     
  202.         /* Find the person's address */
  203.     [recordList getValue:aValue forProperty:[propertyList objectAt:4]at:index];                                                                                                                                  
  204.     [addressField setStringValue:(const char *)[aValue stringValue]];
  205.  
  206.         /* Find the person's city of residence */
  207.     [recordList getValue:aValue forProperty:[propertyList objectAt:5]at:index];
  208.     [cityField setStringValue:(const char *)[aValue stringValue]];
  209.  
  210.  
  211.         /* Find the person's state of residence */
  212.     [recordList getValue:aValue forProperty:[propertyList objectAt:6]at:index];                                                                                                                                  
  213.     [stateField setStringValue:(const char *)[aValue stringValue]];
  214.  
  215.         /* Find the person's zip code */
  216.     [recordList getValue:aValue forProperty:[propertyList objectAt:7]at:index];                                                                                                                                  
  217.     [zipField setStringValue:(const char *)[aValue stringValue]];
  218.     return self;
  219. }
  220.  
  221. /* Add a new record at the specified index. 
  222.  */
  223. - addRecordFrom:sender at:(unsigned)index
  224. {        
  225.     DBRecordList *    recordList;
  226.     List *    propertyList;
  227.     
  228.     recordList = (DBRecordList *)[controller getRecordList];
  229.     propertyList = (List *)[controller getPropertyList];
  230.     
  231.             /* In order to get records in and out, 
  232.              *    we must use a value object all the time
  233.              */
  234.                     
  235.         /* add empty record */
  236.     [recordList insertRecordAt:index];
  237.     if ([self setNewRecordFrom:sender at:index] == nil) {
  238.         return nil;
  239.     }
  240.                                              
  241.     if ([recordList saveModifications] == 0)
  242.         return self;
  243.             
  244.     return nil;    
  245. }
  246.  
  247. /* Update the record specified at index.
  248.  */
  249.  
  250. - updateRecordFrom:sender at:(unsigned) index
  251. {
  252.     DBRecordList *    recordList;
  253.     List * propertyList;    
  254.         
  255.     recordList = (DBRecordList *)[controller getRecordList];
  256.     propertyList = (List *) [controller getPropertyList];
  257.         
  258.     if ([self setNewRecordFrom:sender at:index] == nil) {
  259.         return nil;
  260.     }
  261.     
  262.     if ([recordList saveModifications] == 0)
  263.         return self;
  264.     return nil;    
  265. }
  266.  
  267. /* Get the user input from the text fields. Note that if a field is empty,
  268.  * the operation (either insert or update) would fail. Also, for simplicity,
  269.  * an arbitrary contract number is assigned to new records.
  270.  */
  271. - setNewRecordFrom:sender at:(unsigned)index
  272. {
  273.     DBRecordList *aRecList;
  274.     List *aPropList;
  275.     const char *inputString;
  276.     const char *lastName;
  277.  
  278.     aRecList = (DBRecordList *)[controller getRecordList];
  279.     aPropList = (List *)[controller getPropertyList];
  280.     
  281.     /* get the ssn or author id */
  282.  
  283.      inputString = (const char *)[ssnField stringValue];
  284.     
  285.         /* If the string is empty, abort the operation */
  286.     if  ( !strcmp(inputString,"")){
  287.         NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
  288.         return nil;
  289.      }
  290.     else {    
  291.         [aValue setStringValue:inputString];
  292.         [aRecList setValue:aValue forProperty:[aPropList objectAt:0] at:index];
  293.     }
  294.         
  295.         
  296.         /* set last name */        
  297.     lastName = (const char *)[lnameField stringValue];
  298.     if  ( !strcmp(lastName,"")){
  299.         NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
  300.         return nil;
  301.      } 
  302.     else {
  303.         [aValue setStringValue:lastName];
  304.         [aRecList setValue:aValue forProperty:[aPropList objectAt:1] at:index];             
  305.     }
  306.         
  307.         
  308.         /* set first name */
  309.     inputString = (const char *)[fnameField stringValue];
  310.     if  ( !strcmp(inputString,"")){
  311.         NXRunAlertPanel (NULL, EMPTY_STRING, NULL, NULL, NULL);
  312.         return nil;
  313.      }
  314.     else {
  315.         [aValue setStringValue:(const char *)inputString];
  316.         [aRecList setValue:aValue forProperty:[aPropList objectAt:2] at:index];
  317.         sprintf( cellName, "%s %s", lastName, inputString);
  318.     }
  319.         
  320.             /* set phone number */
  321.     inputString = (const char *)[phoneField stringValue];
  322.     if  ( !strcmp(inputString,"")){
  323.         NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
  324.         return nil;
  325.      }
  326.     else {      
  327.         [aValue setStringValue: inputString];
  328.         [aRecList setValue:aValue forProperty:[aPropList objectAt:3] at:index];
  329.     }
  330.     
  331.             /* set address */
  332.     inputString = (const char *)[addressField stringValue];
  333.     if  ( !strcmp(inputString,"")){
  334.         NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
  335.         return nil;
  336.      }
  337.     else {
  338.         [aValue setStringValue: inputString];
  339.         [aRecList setValue:aValue forProperty:[aPropList objectAt:4] at:index];
  340.     }
  341.  
  342.             /* set city name */
  343.     inputString = (const char *)[cityField stringValue];
  344.     if  ( !strcmp(inputString,"")){
  345.         NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
  346.         return nil;
  347.      } 
  348.     else {
  349.         [aValue setStringValue: inputString];
  350.         [aRecList setValue:aValue forProperty:[aPropList objectAt:5] at:index];
  351.     }
  352.  
  353.             /* set state */
  354.     inputString = (const char *)[stateField stringValue];
  355.     if  ( !strcmp(inputString,"")){
  356.         NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
  357.         return nil;
  358.      }
  359.     else {      
  360.         [aValue setStringValue: inputString];
  361.         [aRecList setValue:aValue forProperty:[aPropList objectAt:6] at:index];
  362.     }
  363.  
  364.             /* set zip code */
  365.     inputString = (const char *)[zipField stringValue];
  366.     if  ( !strcmp(inputString,"")){
  367.         NXRunAlertPanel (NULL,EMPTY_STRING,NULL, NULL, NULL);
  368.         return nil;
  369.      } 
  370.     else {
  371.         [aValue setStringValue: inputString];
  372.         [aRecList setValue:aValue forProperty:[aPropList objectAt:7] at:index]; 
  373.     }
  374.  
  375.  
  376.         /* assign an arbitrary contract number 1 to the new record */
  377.     [aRecList getValue:aValue forProperty:[aPropList objectAt:8] at:index];
  378.     
  379.     if ( ![aValue intValue]) {
  380.         [aValue setIntValue:1];
  381.         [aRecList setValue:aValue forProperty:[aPropList objectAt:8] at:index];
  382.     }
  383.  
  384.     return self;
  385. }
  386.  
  387.  
  388.  
  389. - deleteSelectedRecord:sender
  390. {
  391.     int row;
  392.     DBRecordList * recordList;
  393.  
  394.     row = [cellMatrix selectedRow];
  395.     recordList = (DBRecordList *)[controller getRecordList];
  396.     [recordList deleteRecordAt:row];
  397.     if ([recordList saveModifications] == 0)
  398.         return self;
  399.     else
  400.         return nil;
  401. }
  402.  
  403. @end
  404.